#pragma once
namespace ne{
struct CEvent;
class IComponentObserver;
class ComponentMessenger;
class GameTime;
class InputSystem;
class Component;
class PhysicsWorld;
class GameObject {
public:
	GameObject(void);
	virtual ~GameObject(void);

	Ogre::SceneNode* GetSceneNode() const {return m_sceneNode;}
	Component* GetComponent(int type);
	luabind::object GetComponent(int type, lua_State* L);

	Component* AddComponent(int type);
	luabind::object AddComponent(int type, lua_State* L);
	

	//void AddComponent(Component* component);
	void RemoveComponent(Component* component);
	void RemoveComponent(int type);
	void Shut();

	const Ogre::String& GetId() const { return m_id; }
	void SetId(const Ogre::String& id) { m_id = id; }
	const Ogre::String& GetName() const { return m_name; }
	void SetName(const Ogre::String& name) { m_name = name; }

	Ogre::Vector3 GetPosition() const {return m_sceneNode->getPosition();}
	Ogre::Vector3 GetScale() const {return m_sceneNode->getScale();}
	Ogre::Quaternion GetOrientation()const{return m_sceneNode->getOrientation();}
	void SetPosition(float x, float y, float z);
	void SetPosition(const Ogre::Vector3& vec3);
	void SetOrientation(const Ogre::Quaternion& quat){m_sceneNode->setOrientation(quat);}
	void SetDirection(const Ogre::Vector3& p_dir){m_sceneNode->setDirection(p_dir);}
	void Translate(float x, float y, float z);
	void Translate(const Ogre::Vector3& vec3);
	void SetScale(float x,float y, float z);
	void SetScale(const Ogre::Vector3& scale);
	void Pitch(float p_pitch){m_sceneNode->pitch(Ogre::Radian(p_pitch));}
	void Yaw(float p_yaw){m_sceneNode->yaw(Ogre::Radian(p_yaw));}
	void Roll(float p_roll){m_sceneNode->roll(Ogre::Radian(p_roll));}

	// Member functions overwritten by their lua game object counterpart
	virtual void onStartup(){}
	virtual void onInit(){}
	virtual void onUpdate(){}
	virtual void onSimulation(){}
	virtual void onRemove(){}
	virtual void beginContact(GameObject* gameObject){}
	virtual void endContact(GameObject* gameObject){}

	std::list<Component*>& GetComponents() {return m_components;}

	static void SetBaseSystems(PhysicsWorld* physicsWorld, InputSystem* inputSystem){s_physicsWorld=physicsWorld;s_inputSystem=inputSystem;}
	static void SetSceneManager(Ogre::SceneManager* sceneManager){s_sceneManager=sceneManager;}
	void Notify(CEvent* msg);	// calls the ComponentMessenger and send the message to registered components.
	void Register(IComponentObserver* ob);
	void Unregister(IComponentObserver* ob);
	luabind::object GetAsLua(lua_State* L);

	static Ogre::SceneManager* GetSceneManager(){return s_sceneManager;}
	static PhysicsWorld* GetPhysicsWorld(){return s_physicsWorld;}
	static InputSystem* GetInputSystem(){return s_inputSystem;}

private:
	void RemoveComponentUpdate(void* component);
	void _RemoveComponent(Component* component);	// called from public duplicate to avoid code duplication

	static unsigned int s_counter;
	static Ogre::SceneManager*	s_sceneManager;
	static PhysicsWorld*		s_physicsWorld;
	static InputSystem*			s_inputSystem;
	
	std::list<Component*> m_components;
	Ogre::SceneNode* m_sceneNode;
	GameObject* m_parent;	// parent/child for game objects currently not implemented
	GameObject* m_child;
	Ogre::String m_id;		// is used to find unique game objects
	Ogre::String m_name;	// for display purpose (possibly in a future WYSIWYG editor)
	ComponentMessenger* m_messenger;
};
}